﻿using H.Logs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace H.Logger.Logs
{
    /// <summary>
    /// 日志收集器
    /// </summary>
    public class HLogCollector : ILogCollector
    {
        /// <summary>
        /// 临时存储日志的消息队列
        /// </summary>
        private readonly HLogQueue _LogQueue;

        /// <summary>
        /// 用于取消辅助线程执行的中断源
        /// </summary>
        private readonly CancellationTokenSource _CTS;

        /// <summary>
        /// 存储所有已经注册的监听器
        /// </summary>
        private readonly HashSet<ILogListener> _Listeners = new HashSet<ILogListener>();

        /// <summary>
        /// 用于控制是否暂停监听器输出循环
        /// </summary>
        private readonly ManualResetEvent _ListenerEnable = new ManualResetEvent(false);

        /// <summary>
        /// 存储已经注册的监听器,以使得线程安全
        /// </summary>
        private ILogListener[] _ListenersCopy = new ILogListener[0];



        /// <summary>
        /// 初始化一个新的日志收集器
        /// </summary>
        public HLogCollector()
        {
            _LogQueue = new HLogQueue();
            _CTS = new CancellationTokenSource();
            Thread thread = new Thread(() =>
            {
                while (!_CTS.IsCancellationRequested)
                {
                    _ListenerEnable.WaitOne();
                    ILogListener[] listeners = _ListenersCopy;

                    string logMessage = _LogQueue.Dequeue();

                    foreach (ILogListener listener in listeners)
                    {
                        try
                        {
                            listener.Write(logMessage);
                        }
                        catch (Exception) { }
                    }
                }
            })
            { IsBackground = true };
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }


        ///<inheritdoc/>
        public ILog GetInstance(string sourceName)
        {
            return new HLogClient(this, sourceName);
        }

        /// <summary>
        /// 写入一个新的日志
        /// </summary>
        /// <param name="info"></param>
        internal void PushLog(HLogInfo info)
        {
            _LogQueue.Enqueue(info);
        }

        ///<inheritdoc/>
        public void AddListener(ILogListener listener)
        {
            if (_Listeners.Add(listener))
            {
                _ListenersCopy = _Listeners.ToArray();
            }
            if (_Listeners.Count != 0)
            {
                _ListenerEnable.Set();
                _LogQueue.IsHangUp = false;
            }
        }

        ///<inheritdoc/>
        public void RemoveListener(ILogListener listener)
        {
            if (_Listeners.Remove(listener))
            {
                _ListenersCopy = _Listeners.ToArray();
            }
            if (_Listeners.Count == 0)
            {
                _ListenerEnable.Reset();
                _LogQueue.IsHangUp = true;
            }
        }

        ///<inheritdoc/>
        public void ClearListener()
        {
            _Listeners.Clear();
            _ListenersCopy = new ILogListener[0];
            _ListenerEnable.Reset();
            _LogQueue.IsHangUp = true;
        }

        protected virtual void Dispose(bool disposing)
        {
            _CTS.Cancel();
        }

        public void Dispose()
        {
            Dispose(true);
        }

        ~HLogCollector()
        {
            Dispose(false);
        }
    }
}
